#ifndef BOIDBASE_H
#define BOIDBASE_H

#include <Ogre.h>
#include "OgreOde_Core/OgreOde_Core.h"
#include "Behavior.h"

/**
 * Class BoidBase
 */
class BoidBase;
typedef std::list<BoidBase *> BoidList;

class BoidBase
{
protected:
	OgreOde::Body *mBody;
	typedef std::list<Behavior *> BehaviorList;
	BehaviorList mBehaviorList;

	float mMinSightRadius;
	float mMaxSightRadius;
	float mCosSightAngle;
	bool mNeedRefreshNeighbours;
	BoidList mBoidNeighbours;

public:
	/// constructor.
	BoidBase(OgreOde::Body *mBody);

	/// destructor.
	~BoidBase();

	/// returns the position of this boid.
	const Ogre::Vector3& getPosition() const
	{
		return mBody->getPosition();
	}

	Ogre::String getName() const
	{
		return mBody->getName();
	}

	/// returns the facing vector of this boid.
	Ogre::Vector3 getForwardVector() const
	{
		return mBody->getOrientation() * Ogre::Vector3::UNIT_Z;
	}

	/// returns the up vector of this boid.
	Ogre::Vector3 getUpVector() const
	{
		return mBody->getOrientation() * Ogre::Vector3::UNIT_Y;
	}

	/// returns the right vector of this boid.
	Ogre::Vector3 getRightVector() const
	{
		return mBody->getOrientation() * Ogre::Vector3::UNIT_X;
	}

	/// returns the velocity of this boid.
	virtual const Ogre::Vector3& getVelocity() const = 0;

	/// steer boid base on desired steering vector.
	virtual void steerBoid(const Ogre::Vector3& desiredVector) = 0;

// Sight Range Methods
	/// set sight range.
	void setSightRange(float minRadius, float maxRadius, float angle)
	{
		mMinSightRadius = minRadius;
		mMaxSightRadius = maxRadius;
		mCosSightAngle = Ogre::Math::Cos(angle);
		mNeedRefreshNeighbours = true;
	}

	/// check if the given boid is in the neighborhood.
	bool isInNeighborhood(const BoidBase *other, float minDistance, float maxDistance, float cosMaxAngle) const;

	/// returns the neighbors of this boid.
	const BoidList& getNeighbors() const;

// Behavior Methods
	/// add behavior.
	Behavior *addBehavior(BehaviorType type);

	/// remove specific behavior.
	void removeBehavior(Behavior *behavior);

	/// get behaviors.
	const BehaviorList &getBehaviors();

	/// returns the number of behaviors.
	int getBehaviorCount();

	/// clears behavior list.
	void clearBehaviors();

	/// returns the combined weighted desired steering vector.
	Ogre::Vector3 getBehaviorResult();
};

#endif // BOIDBASE_H
